# Table of Contents
# 의존성 주입
의존성 주입(Dependency Injection)
에 대해 자세히 알아본다.
# 의존성 주입 방법
크게 세 가지 방법으로 의존성을 주입할 수 있다.
# 필드 주입
우선 필드에 빈을 직접 주입할 수 있다.
@Controller
public class MemberController {
@Autowired
private MemberService memberService;
}
배열형 멤버변수에 @Autowired
를 붙이면 이 배열의 타입과 호환되는 모든 빈을 주입시켜준다.
@Controller
public class MemberController {
@Autowired
private MemberService[] memberService;
}
public interface MemberService {
// ...
}
public class MyMemberService implements MemberService {
// ...
}
public class YourMemberService implements MemberService {
// ...
}
List
형 멤버변수에 @Autowired
를 붙이면 이 리스트의 타입과 호환되는 모든 빈을 주입시켜준다.
@Controller
public class MemberController {
@Autowired
private List<MemberService> memberService;
}
Map
형 멤버변수에 @Autowired
를 붙이면 이 리스트의 타입과 호환되는 모든 빈을 주입시켜준다. 이 때 빈의 이름이 Map
의 키 값이 된다.
@Controller
public class MemberController {
@Autowired
private Map<MemberService> memberService;
}
@Autowired
는 필요한 빈을 찾지 못하면 예외를 던진다. 예외를 발생시키지 않으며면 required
속성을 false
로 지정하면 된다.
@Controller
public class MemberController {
@Autowired(required = false)
private MemberService memberService; // null
}
# 생성자 주입
생성자 주입
은 스프링에서 가장 권장되는 의존성 주입 방법이다.
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
# Setter 주입
Setter 메소드로도 의존성을 주입할 수 있다.
@Controller
public class MemberController {
private MemberService memberService;
@Autowired
public void setMemberService(MemberService memberService) {
this.memberService = memberService;
}
}
# Lombok
Lombok
라이브러리를 사용하는 경우 @RequiredArgsConstructor
어노테이션으로 의존성을 주입할 수 있다. 이때 필드는 반드시 final
로 설정해야한다.
import lombok.RequiredArgsConstructor;
@Controller
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
}
# @Autowired
@Autowired
는 타입을 기준으로 빈을 찾아 주입한다. 이 어노테이션은 스프링 프레임워크에 포함되어있다.
import org.springframework.beans.factory.annotation.Autowired;
@Repository
public class PostRepository {
@Autowired
private FileManager fileManager;
}
# @Primary
만약 컨테이너에 같은 타입의 빈이 여러 개 존재한다면 의존성 주입이 제대로 되지 않을 수도 있다. 예제를 살펴보자.
@Repository
public class PostRepository {
@Autowired
private FileManager fileManager;
}
FileManager
는 인터페이스고 여러 구현체들이 빈으로 등록되어있을 수 있다.
public interface FileManager {
// ..
}
@Component
public class MyFileManager implements FileManager {
// ..
}
@Component
public class YourFileManager implements FileManager {
// ..
}
이 경우 @Primary
를 사용하면 여러 빈이 주입될 수 있을 때 특정 빈에 우선권을 부여할 수 있다.
import org.springframework.context.annotation.Primary;
@Component
@Primary
public class MyFileManager implements FileManager {
// ..
}
# @Qualifier
@Qualifier
를 사용하여 후보 빈을 명시할 수도 있다. 이 어노테이션은 스프링 프레임워크에 포함되어있다.
import org.springframework.beans.factory.annotation.Qualifier;
@Component
@Qualifier("myFileManager")
public class MyFileManager implements FileManager {
// ..
}
import org.springframework.beans.factory.annotation.Qualifier;
@Repository
public class PostRepository {
private FileManager fileManager;
@Autowired
public PostRepository(@Qualifier("myFileManager") FileManager fileManager) {
this.FileManager = fileManager;
}
}
# @Resource
@Resource
는 스프링 프레임워크가 아닌 자바에 포함된 어노테이션으로 이름을 통해 빈을 탐색한다. 스프링 프레임워크의 @Autowired
와 @Qualifier
를 합친 것으로 생각하면 된다.
import javax.annotation.Resource;
@Repository
public class PostRepository {
private FileManager fileManager;
@Resource(name = "myFileManager")
public PostRepository(FileManager fileManager) {
this.FileManager = fileManager;
}
}
# @Inject, @Qualifier
@Inject
도 스프링 프레임워크가 아닌 자바에 포함된 어노테이션이다. 이 어노테이션도 @Autowired
와 마찬가지로 일단 타입으로 빈을 탐색한다.
import javax.inject.Inject;
@Repository
public class PostRepository {
private FileManager fileManager;
@Inject
public PostRepository(FileManager fileManager) {
this.FileManager = fileManager;
}
}
이 어노테이션 역시 타입이 같은 빈이 여러 개일 때 다른 방법을 구사해야한다. 이 때는 @Qualifier
를 사옹하여 커스텀 어노테이션을 작성하면 된다.
import javax.inject.Qualifier;
@Qualifier
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Document
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFileManagerAnnotation
@Component
@MyFileManagerAnnotation
public class MyFileManager implements FileManager {
// ..
}
import javax.inject.Inject;
@Repository
public class PostRepository {
private FileManager fileManager;
@Inject
@MyFileManagerAnnotation
public PostRepository(FileManager fileManager) {
this.FileManager = fileManager;
}
}
WARNING
스프링 프레임워크의 org.springframework.beans.factory.annotation.Qualifier
가 아니라 Java의 javax.inject.Qualifier
를 사용한다는 점에 주의하자.